#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "symbol.h"
#include "lex.h"


extern Stack global_sym_stack, local_sym_stack;
extern Type char_pointer_type;                  // 字符串指针
extern Type int_type;                           // int 类型
extern Type default_func_type;                  // 缺省函数类型


TkWord *tk_hashtable[MAXKEY]; // 单词哈希表
DynArray tktable;             // 单词表
char *filename;               // 文件名
int line_num;                 // 第几行
int token;                    // 获取的token
char ch;                      // 获取的单个字符
DynString tkstr;
DynString sourcestr;
int tkvalue;
extern FILE *fin;
extern void syntax_indent();

/*
初始化动态字符串存储容量
pstr:动态字符串存储结构
initsize:字符串初始化分配空间
*/
void dynstring_init(DynString *pstr, int initsize)
{
    if (pstr != NULL)
    {
        pstr->data = (char *)malloc(sizeof(char) * initsize);
        pstr->count = 0;
        pstr->capacity = initsize;
    }
}

/*
释放动态字符串的空间
pstr:动态字符串存储结构
*/
void dynstring_free(DynString *pstr)
{
    if (pstr != NULL)
    {
        if (pstr->data)
        {
            free(pstr->data);
        }
        pstr->count = 0;
        pstr->capacity = 0;
    }
}

/*
重置动态字符串，先释放在重新初始化
pstr:动态字符串存储结构
*/
void dynstring_reset(DynString *pstr)
{
    dynstring_free(pstr);
    dynstring_init(pstr, 8);
}

/*
重新分配动态字符串容量
pstr:动态字符串存储结构
new_size：动态字符串新长度
*/
void dynstring_realloc(DynString *pstr, int new_size)
{
    int capacity;
    char *data;
    capacity = pstr->capacity;
    while (capacity < new_size)
    {
        capacity = capacity * 2;
    }
    data = realloc(pstr->data, capacity);
    if (!data)
    {
        errorMsg("%s", "内存分配失败");
    }
    pstr->capacity = capacity;
    pstr->data = data;
}

/*
追加单个字符到动态字符串
pstr :动态字符串存储结构
ch:所要追加的字符
*/
void dynstring_chcat(DynString *pstr, char ch)
{
    int count;
    count = pstr->count + 1;
    if (count > pstr->capacity)
    {
        dynstring_realloc(pstr, count);
    }
    pstr->data[count - 1] = ch;
    pstr->count = count;
}

/*
重新分配动态数组容量
parr :动态数组存储结构
new_size:动态数组最新元素个数
*/
void dynarray_realloc(DynArray *parr, int new_size)
{
    int capacity;
    void *data;
    capacity = parr->capacity;
    while (capacity < new_size)
    {
        capacity = capacity * 2;
    }
    data = realloc(parr->data, capacity * sizeof(void *));
    if (!data)
    {
        errorMsg("%s", "内存分配失败");
    }
    parr->capacity = capacity;
    parr->data = data;
}

/*
追加动态数组元素
parr:动态数组存储结构
data:所要追加的新元素
*/
void dynarray_add(DynArray *parr, void *data)
{
    int count;
    count = parr->count + 1;
    if (count > parr->capacity)
    {
        dynarray_realloc(parr, count);
    }
    parr->data[count - 1] = data;
    parr->count = count;
}

/*
初始化动态数组存储容量
parr:动态数组存储结构
initsize:动态数组初始化分配空间
*/
void dynarray_init(DynArray *parr, int initsize)
{
    if (parr != NULL)
    {
        parr->data = (void **)malloc(sizeof(void *) * initsize);
        parr->count = 0;
        parr->capacity = initsize;
    }
}

/*
释放动态数组使用的内存空间
parr:动态数组存储结构
*/
void dynarray_free(DynArray *parr)
{
    void **p;
    for (p = parr->data; parr->count; ++p, --parr->count)
    {
        if (*p)
        {
            free(*p);
        }
    }
    free(parr->data);
    parr->data = NULL;
}

/*
动态数组元素搜索,动态数组里面保存的是整数，实际应该是int **
parr :动态数组存储结构
key:要查找的元素
*/
int dynarray_search(DynArray *parr, int key)
{
    int i;
    int **p;
    p = (int **)parr->data;
    for (i = 0; i < parr->count; ++i, p++)
    {
        if (key == **p)
        {
            return i;
        }
    }
    return -1;
}

/*
计算哈希地址
key:哈希关键字
MAXKEY:哈希表长度
*/
int elf_hash(char *key)
{
    int h = 0, g;
    while (*key)
    {
        h = (h << 4) + *key++;
        g = h & 0xf0000000;
        if (g)
        {
            h ^= g >> 24;
        }
        h &= ~g;
    }
    return h % MAXKEY;
}

// 运算符，关键字，常量直接放入单词表
// tp：指向单词结构体的指针
TkWord *tkword_direct_insert(TkWord *tp)
{
    int keyno;
    dynarray_add(&tktable, tp);
    keyno = elf_hash(tp->spelling);
    tp->next = tk_hashtable[keyno];
    tk_hashtable[keyno] = tp;
    return tp;
}

/*
在单词表中查找单词
p:要查找的单词
keyno:要查找单词的哈希值
*/
TkWord *tkword_find(char *p, int keyno)
{
    TkWord *tp = NULL, *tp1 = NULL;
    for (tp1 = tk_hashtable[keyno]; tp1; tp1 = tp1->next)
    {
        if (!strcmp(p, tp1->spelling))
        {
            token = tp1->tkcode;
            tp = tp1;
        }
    }
    return tp;
}

/*
分配堆内存，并将数据初始化为'0'
size：分配内存大小
*/
void *mallocz(int size)
{
    void *ptr;
    ptr = malloc(size);
    if (!ptr && size)
    {
        errorMsg("%s", "内存分配失败");
    }
    memset(ptr, 0, size);
    return ptr;
}

/*
标志符插入单词表，先查找，查找不到再插入单词表
*/
TkWord *tkword_insert(char *p)
{
    TkWord *tp;
    int keyno;
    char *s;
    char *end;
    int length;
    keyno = elf_hash(p);
    tp = tkword_find(p, keyno);
    if (tp == NULL)
    {
        length = strlen(p);
        tp = (TkWord *)mallocz(sizeof(TkWord) + length + 1);
        tp->next = tk_hashtable[keyno];
        tk_hashtable[keyno] = tp;
        dynarray_add(&tktable, tp);
        tp->tkcode = tktable.count - 1;
        s = (char *)tp + sizeof(TkWord);
        tp->spelling = (char *)s;
        for (end = p + length; p < end;)
        {
            *s++ = *p++;
        }
        *s = (char)'\0';
    }
    return tp;
}

/*
词法分析初始化
*/
void init_lex(void)
{
    TkWord *tp;
    static TkWord keywords[] = {
        {TK_PLUS, NULL, "+"},
        {TK_MINUS, NULL, "-"},
        {TK_STAR, NULL, "*"},
        {TK_DIVIDE, NULL, "/"},
        {TK_MOD, NULL, "%"},
        {TK_EQ, NULL, "=="},
        {TK_NEQ, NULL, "!="},
        {TK_LT, NULL, "<"},
        {TK_LEQ, NULL, "<="},
        {Tk_GT, NULL, ">"},
        {TK_GEQ, NULL, ">="},
        {TK_ASSIGN, NULL, "="},
        {TK_POINTSTO, NULL, "->"},
        {TK_DOT, NULL, "."},
        {TK_AND, NULL, "&"},
        {TK_OPENPA, NULL, "("},
        {TK_CLOSEPA, NULL, ")"},
        {TK_OPENBR, NULL, "["},
        {TK_CLOSEBR, NULL, "]"},
        {TK_BEGIN, NULL, "{"},
        {TK_END, NULL, "}"},
        {TK_SEMICOLON, NULL, ";"},
        {TK_COMMA, NULL, ","},
        {TK_ELLIPSIS, NULL, "..."},
        {TK_EOF, NULL, "End_Of_File"},

        {TK_CINT, NULL, "整型常量"},
        {TK_CCHAR, NULL, "字符常量"},
        {TK_CSTR, NULL, "字符串常量"},

        {KW_CHAR, NULL, "char"},
        {KW_SHORT, NULL, "short"},
        {KW_INT, NULL, "int"},
        {KW_VOID, NULL, "void"},
        {KW_STRUCT, NULL, "struct"},

        {KW_IF, NULL, "if"},
        {KW_ELSE, NULL, "else"},
        {KW_FOR, NULL, "for"},
        {KW_CONTINUE, NULL, "continue"},
        {KW_BREAK, NULL, "break"},
        {KW_RETURN, NULL, "return"},
        {KW_SIZEOF, NULL, "sizeof"},
        {KW_ALIGN, NULL, "__align"},
        {KW_CDECL, NULL, "__cdecl"},
        {KW_STDCALL, NULL, "__stdcall"},
        {0, NULL, NULL}};
    dynarray_init(&tktable, 8);
    for (tp = &keywords[0]; tp->spelling != NULL; tp++)
    {
        tkword_direct_insert(tp);
    }
}

/*
异常处理
stage:编译阶段还是链接阶段
level:错误级别
fmt:参数输出的格式
ap：可变参数列表
*/
void handle_except(int stage, int level, char *fmt, va_list ap)
{
    char buf[1024];
    vsprintf(buf, fmt, ap);
    if (stage == STAGE_COMPILE)
    {
        if (level == LEVEL_WARNING)
        {
            printf("%s(第%d行)：编译警告:%s!\n", filename, line_num, buf);
        }
        else
        {
            printf("%s(第%d行):编译错误%s!\n", filename, line_num, buf);
            exit(-1);
        }
    }
    else
    {
        printf("链接错误:%s!\n", buf);
        exit(-1);
    }
}

/*
编译警告处理
fmt :参数输出的格式
ap:可变参数列表
*/
void warning(char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    handle_except(STAGE_COMPILE, LEVEL_WARNING, fmt, ap);
    va_end(ap);
}

/*
编译致命错误处理
fmt:参数输出的格式
ap:可变参数列表
*/
void errorMsg(char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    handle_except(STAGE_COMPILE, LEVEL_ERROR, fmt, ap);
    va_end(ap);
}

/*
提示错误，此处缺少某个语法成分
msg:需要什么语法成分
*/
void except(char *msg)
{
    errorMsg("缺少%s", msg);
}

/*
取得单词v所代表的源码字符串
v:单词编号
*/
char *get_tkstr(int v)
{
    if (v > tktable.count)
    {
        return NULL;
    }
    else if (v >= TK_CINT && v <= TK_CSTR)
    {
        return sourcestr.data;
    }
    else
    {
        return ((TkWord *)tktable.data[v])->spelling;
    }
}

/*
跳过单词c，取下一个单词，如果当前不是单词c，提示错误
c：要跳过的单词
*/
void skip(int c)
{
    if (token != c)
    {
        errorMsg("缺少'%s'", get_tkstr(c));
    }
    get_token();
}

/*
链接错误处理
fmt:参数输出的格式
ap：可变参数列表
*/
void link_error(char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    handle_except(STAGE_LINK, LEVEL_ERROR, fmt, ap);
    va_end(ap);
}

/*
从源文件中读取一个字符
*/
void getch(void)
{
    ch = getc(fin); // 文件尾返回EOF，其它返回实际字节值
}

/*
忽略空格,tab和回车
*/
void skip_white_space()
{
    while (ch == ' ' || ch == '\t' || ch == '\n')
    {
        if (ch == '\n')
        {
            line_num++;
        }
        printf("%c", ch);
        getch();
    }
}

/*
判断c是否为字母或者是下划线
c:字符值
*/
int is_nodigit(char c)
{
    return (c >= 'a' && c <= 'z') ||
           (c >= 'A' && c <= 'Z') ||
           c == '_';
}

/*
判断字符c是否为数字
c:字符
*/
int is_digit(char c)
{
    return c >= '0' && c <= '9';
}

/*
解析标志符,字母数字，下划线，以字符，下划线开头
*/
void parse_identifier()
{
    dynstring_reset(&tkstr);
    dynstring_chcat(&tkstr, ch);
    getch();
    while (is_nodigit(ch) || is_digit(ch))
    {
        dynstring_chcat(&tkstr, ch);
        getch();
    }
    dynstring_chcat(&tkstr, '\0');
}

/*
解析整型常量，以数字开头，可以包含小数点和数字
*/
void parse_num()
{
    dynstring_reset(&tkstr);
    dynstring_reset(&sourcestr);
    do
    {
        dynstring_chcat(&tkstr, ch);
        dynstring_chcat(&sourcestr, ch);
        getch();
    } while (is_digit(ch));
    if (ch == '.')
    {
        do
        {
            dynstring_chcat(&tkstr, ch);
            dynstring_chcat(&sourcestr, ch);
            getch();
        } while (is_digit(ch));
    }
    dynstring_chcat(&tkstr, '\0');
    dynstring_chcat(&sourcestr, '\0');
    tkvalue = atoi(tkstr.data);
}

/*
解析字符常量，字符串常量，以'或者"开头
sep 字符常量界符标志为单引号(')
    字符串常量界符标识为双引号(")
*/
void parse_string(char sep)
{
    char c;
    dynstring_reset(&tkstr);
    dynstring_reset(&sourcestr);
    dynstring_chcat(&sourcestr, sep);
    getch();
    for (;;)
    {
        if (ch == sep)
        {
            break;
        }
        else if (ch == '\\')
        {
            dynstring_chcat(&sourcestr, ch);
            getch();
            switch (ch)
            {
            case '0':
                c = '\0';
                break;
            case 'a':
                c = '\a';
                break;
            case 'b':
                c = '\b';
                break;
            case 't':
                c = '\t';
                break;
            case 'n':
                c = '\n';
                break;
            case 'v':
                c = '\v';
                break;
            case 'f':
                c = '\f';
                break;
            case 'r':
                c = '\r';
                break;
            case '\"':
                c = '\"';
                break;
            case '\'':
                c = '\'';
                break;
            case '\\':
                c = '\\';
                break;
            default:
                c = ch;
                if (c > '!' && c <= '~')
                {
                    warning("非法转义字符:\'\\%c\'", c);
                }
                else
                {
                    warning("非法转义字符：\'\\0x%x\'", c);
                }
                break;
            }
            dynstring_chcat(&tkstr, c);
            dynstring_chcat(&sourcestr, ch);
            getch();
        }
        else
        {
            dynstring_chcat(&tkstr, ch);
            dynstring_chcat(&sourcestr, ch);
            getch();
        }
    }
    dynstring_chcat(&tkstr, '\0');
    dynstring_chcat(&sourcestr, sep);
    dynstring_chcat(&sourcestr, '\0');
    getch();
}

/*
解析注释
*/
void parse_comment()
{
    getch();
    do
    {
        do
        {
            if (ch == '\n' || ch == '*' || ch == TK_EOF)
            {
                break;
            }
            else
            {
                getch();
            }

        } while (1);
        if (ch == '\n')
        {
            line_num++;
            getch();
        }
        else if (ch == '*')
        {
            getch();
            if (ch == '/')
            {
                getch();
                return;
            }
        }
        else
        {
            errorMsg("%s", "一直到文件尾未看到配对的注释结束符");
            return;
        }
    } while (1);
}

/*
预处理，忽略空白字符及注释
*/
void preprocess()
{
    while (1)
    {
        if (ch == ' ' || ch == '\t' || ch == '\n')
        { // 忽略空白字符，\t字符，换行字符
            skip_white_space();
        }
        else if (ch == '/')
        {
            getch();
            if (ch == '*')
            { // 忽略注释
                parse_comment();
            }
            else
            {
                ungetc(ch, fin); // 不是注释，那么将字符重新退回到输入流中
                ch = '/';
                break;
            }
        }
        else
        {
            break;
        }
    }
}

/*
取出单词
*/
void get_token(void)
{
    preprocess();
    switch (ch)
    {
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
    case 'i':
    case 'j':
    case 'k':
    case 'l':
    case 'm':
    case 'n':
    case 'o':
    case 'p':
    case 'q':
    case 'r':
    case 's':
    case 't':
    case 'u':
    case 'v':
    case 'w':
    case 'x':
    case 'y':
    case 'z':
    case 'A':
    case 'B':
    case 'C':
    case 'D':
    case 'E':
    case 'F':
    case 'G':
    case 'H':
    case 'I':
    case 'J':
    case 'K':
    case 'L':
    case 'M':
    case 'N':
    case 'O':
    case 'P':
    case 'Q':
    case 'R':
    case 'S':
    case 'T':
    case 'U':
    case 'V':
    case 'W':
    case 'X':
    case 'Y':
    case 'Z':
    case '_':
    {
        TkWord *tp;
        parse_identifier();
        tp = tkword_insert(tkstr.data);
        token = tp->tkcode;
        break;
    }
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
        parse_num();
        token = TK_CINT;
        break;
    case '+':
        getch();
        token = TK_PLUS;
        break;
    case '-':
        getch();
        if (ch == '>')
        {
            token = TK_POINTSTO;
            getch();
        }
        else
        {
            token = TK_MINUS;
        }
        break;
    case '/':
        token = TK_DIVIDE;
        getch();
        break;
    case '%':
        token = TK_MOD;
        getch();
        break;
    case '=':
        getch();
        if (ch == '=')
        {
            token = TK_EQ;
            getch();
        }
        else
        {
            token = TK_ASSIGN;
        }
        break;
    case '!':
        getch();
        if (ch == '=')
        {
            token = TK_NEQ;
            getch();
        }
        else
        {
            errorMsg("暂不支持'!'(非法操作符)");
        }
        break;
    case '<':
        getch();
        if (ch == '=')
        {
            token = TK_LEQ;
            getch();
        }
        else
        {
            token = TK_LT;
        }
        break;
    case '>':
        getch();
        if (ch == '=')
        {
            token = TK_GEQ;
            getch();
        }
        else
        {
            token = Tk_GT;
        }
        break;
    case '.':
        getch();
        if (ch == '.')
        {
            getch();
            if (ch != '.')
            {
                errorMsg("%s", "省略号拼写错误");
            }
            else
            {
                token = TK_ELLIPSIS;
                getch();
            }
        }
        else
        {
            token = TK_DOT;
        }
        break;
    case '&':
        token = TK_AND;
        getch();
        break;
    case ';':
        token = TK_SEMICOLON;
        getch();
        break;
    case ']':
        token = TK_CLOSEBR;
        getch();
        break;
    case '}':
        token = TK_END;
        getch();
        break;
    case ')':
        token = TK_CLOSEPA;
        getch();
        break;
    case '[':
        token = TK_OPENBR;
        getch();
        break;
    case '{':
        token = TK_BEGIN;
        getch();
        break;
    case ',':
        token = TK_COMMA;
        getch();
        break;
    case '(':
        token = TK_OPENPA;
        getch();
        break;
    case '*':
        token = TK_STAR;
        getch();
        break;
    case '\'':
        parse_string(ch);
        token = TK_CCHAR;
        tkvalue = *(char *)tkstr.data;
        break;
    case '\"':
    {
        parse_string(ch);
        token = TK_CSTR;
        break;
    }
    case EOF:
        token = TK_EOF;
        break;
    default:
        errorMsg("不认识的字符:\\x%02x", ch);
        break;
    }
    syntax_indent();
}

/*
初始化
*/
void init()
{
    line_num = 1;
    init_lex();
    stack_init(&local_sym_stack,8);
    stack_init(&global_sym_stack,8);
    // sym_sec_rdata=sec_sym_put(".rdata",0);


    int_type.t=T_INT;
    char_pointer_type.t=T_CHAR;
    // mk_pointer(&char_pointer_type);
    default_func_type.t = T_FUNC;
    default_func_type.ref=sym_push(SC_ANOM,&int_type,KW_CDECL,0);

}

/*
扫尾清理工作
*/
void cleanup(void)
{
    int i;
    sym_pop(&global_sym_stack,NULL);
    stack_destroy(&local_sym_stack);
    stack_destroy(&global_sym_stack);

    printf("\ntktable.count=%d\n", tktable.count);
    for (i = TK_IDENT; i < tktable.count; i++)
    {
        free(tktable.data[i]);
    }
    free(tktable.data);
}

/*
为词法着色
*/
void color_token(int lex_state)
{
    char *p;
    char *color;
    switch (lex_state)
    {
    case LEX_NORMAL:
        if (token >= TK_IDENT)
        {
            color = CLR_RED;
        }
        else if (token >= KW_CHAR)
        {
            color = CLR_BLUE;
        }
        else if (token >= TK_CINT)
        {
            color = CLR_YELLOW;
        }
        else
        {
            color = CLR_GREEN;
        }
        p = get_tkstr(token);
        printf("%s%s", color, p);
        break;

    case LEX_SEP:
        printf("%s%c", CLR_PURPLE, ch);
        break;
    }
}

void expect(char *msg)
{
    errorMsg("缺少%s", msg);
}
